Skip to content

[feat] timeline: add editable captions and text overlays - #193

Merged
kunkunblueberry merged 19 commits into
ThinkFlowLab:mainfrom
Qing7364:codex/issue-87-timeline-text
Nov 10, 2026
Merged

kunkunblueberry merged 19 commits into
ThinkFlowLab:mainfrom
Qing7364:codex/issue-87-timeline-text

Conversation

@Qing7364

@Qing7364 Qing7364 commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Add editable timed captions and text overlays through shared UI and Agent commands, with retained text/font dependencies, save/reopen, portable editing, preview and browser-composed MP4.

Current delivery

  • Final head: 9db7cf83333f2e189ad89bcad5d0fbbe70f33d3e.
  • At the contributor's explicit request, all 18 PR commits were recreated with Author and Committer email vera.xpq@gmail.com; the screenshot/documentation commit uses the same email (19/19). Each historical tree, message, name, timestamp and merge relationship is preserved. Upstream main commits were not rewritten. An exact old-SHA force-with-lease protects the branch update; the original history is retained in a verified local bundle and backup ref.
  • The email-only equivalent of the Windows-tested source a71d3b1e is 79eac341866e44542d84c57b375df9eb459580f3; original delivery 59fc9aac maps to 0e94abb3b2a92c6d41ad8a1a1d8077469cd8a672. Historical acceptance records keep their actual original SHAs. The versioned record and complete SHA mapping explain the boundary.
  • The final commit adds two existing screenshots and documentation only. All 886 existing runtime/test/dependency/build/config inputs remain identical to the Windows-tested source. No Windows tests were rerun.
  • Integrated main: e0b411f151dfe48250c4651c0d820e05179f41ce.
  • Final-head Release checks #182: SUCCESS — Python 1578 passed / 98 existing skips / 1 warning, Node 744 passed, 19/19 browser workflows, build, contracts, bilingual/locale/manifest/import checks, Linux installed wheel, voice and assistant workflows all passed. The actual CI checkout d9ccc2347835e713c031e1c63eb00403e5eaf3ef has the same complete tree as this head. Marked Ready for review after those checks passed.
  • Existing GPG signing configuration was preserved and signatures regenerated. The local signing key retains its work-email user ID; cryptographic validity and GitHub account verification are distinct. GitHub currently reports unknown_key for the preserved signing key; this is not claimed as GitHub Verified. Author/Committer email verification is complete.
  • The maintainer's CHANGES_REQUESTED remains for re-review; no review was dismissed or PR merged.

Existing visual evidence

These are unchanged November 9 macOS focused-regression captures, reused without recapture. They show the cross-project editable-text scenario, properties, package controls and completed MP4 publication in both interface languages. The visible stale-draft notice is retained. Chinese text is synthetic project content, so it remains Chinese in the English interface. The tiny fixture output rounds to 0.00 MB; it is not a missing file.

The archive report identifies macOS/HeadlessChrome 145 but does not embed a source Git revision. These are historical visual evidence, not a claim of a new current-head or Windows run. Image hashes and capture limitations are in the linked validation record.

Chinese UI

Chinese editable timeline text and package controls

English UI

English editable timeline text and package controls

Validation and retained acceptance

  • Windows native seven modules: 154 passed / 0 failed / 0 skipped, including all 11 installation + 12 cleanup WinAPI windows and real OpenCode fresh/resume/watchdog gates.
  • Windows 0.1.2 installed wheel: 308 passed / 0 failed / 0 skipped in 12 affected modules, including real dsh/SDK OWNER RIGHTS and outside-write rejection. Fresh install, no-Node checks, byte audit and bilingual installed-wheel voice workflows passed.
  • Wheel: opendirector-0.1.2-py3-none-win_amd64.whl, 97,623,495 bytes, SHA-256 8ae498f7748edbcbdb46a9945fbaf14f7934e11d858d751e3fcfb6791736007c. Its 135 Python files and 31 bundled resources match the frozen source/install. The 886-input manifest hash is 36ec56252d87ada89d1de6feac19830ac77cfd77e9e232906e44d67a74926fb0.
  • Prior final-head Release checks #179 on original 59fc9aac: 1578 Python passed / 98 existing skips / 1 warning, 744 Node passed, 19/19 standard browser workflows, production build, contracts, 3002 bilingual keys, locale/manifest, import boundaries, installed Linux wheel/no Node, voice and assistant workflows all passed. The successful new-head run is recorded separately above.
  • Issue [feat] 时间线:支持可编辑字幕与文字叠加 #87 acceptance remains recorded at its actual tested versions: equivalent UI/Agent editing, timing/style/order/locks, undo/redo, authoritative save/reopen, Chinese preview/actual MP4, immutable old publication provenance, protected text/font dependencies and editable package round trips. Unsupported FCPXML/legacy ZIP actions are disabled and rejected. Browser participation is still required for MP4 composition.
  • Review fixes retain shared limits, Pydantic >=2.12, bilingual error codes, stale-projection/autosave protection, safe native resume and fail-closed uncertain ACL installation. Main's voice/Kling and result-download security behavior are preserved. The assistant default-selection fix and voice browser repairs have positive and negative controls in the record.

Evidence limits

The first merged native attempt (153 passed / 1 OpenCode watchdog failure / 0 skipped), unchanged-timeout isolated pass and final serial 154-pass run are retained. Resource contention is suspected, not a proven reconstruction. No skip gates, assertions or sandbox protections were relaxed.

OpenCode/dsh are real CLIs with simulated model HTTP; Codex/Claude/ACP protocol cases use subprocess fixtures. Kling/voice providers are simulated, not paid-provider quality verification. Windows file-symlink error 1314 remains documented; native ACL support is bounded to supported current-owner local NTFS descriptors/oplocks. Linux's 98 skips comprise 92 Windows-only cases and six opt-in CLI gates; required OpenCode/dsh Windows gates actually ran. Historical 1080p/2000-cue/full-Windows/old-wheel results are not relabeled as new runs.

Versioned validation contains commands, source boundaries, the complete native matrix, preserved failures, all Linux skip reasons and historical media results. Large raw logs, environments and credentials remain outside Git.

Refs: #87

## summary

- Keep assistant visibility independent from asset search and generation
  history, with adjacent desktop panels and usable narrow layouts.
- Cover drafts, dismissal paths, both locales and active reply/generation
  preservation in isolated browser tests.
- Make related shortcut/navigation tests wait for readiness and select
  their expected locale, and document the new validation entry point.

## validation

- npm test: 585 passed
- npm run build
- npm run check:i18n: 2862 keys, 0 problems
- Chromium browser checks: assistant auxiliary panels, double Shift and
  running-reply navigation (isolated API and model fixtures)

Fixes: ThinkFlowLab#118
## summary

- Retain timed text, style, layer order, fonts and source assets in
  editable timelines through shared UI and Agent commands.
- Share Chinese text layout between preview and MP4 export and retain
  exact editor revisions for each published output.
- Exchange editable timeline packages with resource validation,
  dependency protection and recoverable imports.
- Add bilingual UI, regression coverage and acceptance documentation.

## validation

- npm test: 621 passed.
- Related Python checks across nine test files: 189 passed.
- Generated contracts, i18n catalogs and frontend build passed.
- Prior macOS x64 and native arm64 browser/wheel acceptance is recorded
  in docs/development/issue-87-validation.md.
- Windows acceptance is pending; the full Python suite has documented
  baseline failures and an interrupted native integration run.

Refs: ThinkFlowLab#87
@hsliuustc0106 hsliuustc0106 added type:feat New capability or behaviour area:timeline Timeline, subtitles and export area:canvas Canvas, nodes and direct manipulation labels Nov 8, 2026
## summary

- Add handle-relative execution file I/O on Windows and pin POSIX roots,
  rejecting links, redirected execution roots and nonregular inputs.
- Initialize OWNER RIGHTS directories before file creation, guard DACL
  updates, coordinate leases across processes and clean up failures.
  Preserve denies and restricted-token capability boundaries.
- Fix native session resume, private skill snapshots, atomic JSON
  replacement, history cache verification and Windows launcher quoting.
- Keep active hidden-source references and structured prompts independent
  of display visibility, while preserving accepted input snapshots.
- Add platform and native sandbox regressions and record timeline text,
  editable-package, installed-wheel and POSIX validation limits.

## validation

- Staged code and tests match the frozen final validation snapshot.
- Full Python: 1149 passed, 5 existing skips; related tests: 95 passed.
- Fresh installed wheel: 403 passed, 5 existing skips, including real
  dsh and Jiuwen engine tests using local model fixtures.
- Node: 621 passed; seven browser suites passed; contracts and i18n passed.
- Real Linux: 45 passed, 49 Windows-only skips; 2000 rejected inputs and
  100 file round trips kept the descriptor count at four.
- Four Windows skips require POSIX change time; one file-symlink case
  remains limited by Windows error 1314. Existing skip gates are unchanged.

Refs: ThinkFlowLab#87

@kunkunblueberry kunkunblueberry left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审查结论:draft + 与 main 冲突,且发现若干合并前需要处理的问题,本轮不合并。

1. blocker — 与 main 冲突

GitHub 报 CONFLICTING / DIRTY;git merge-tree 确认约 24 个文件有真实冲突(apps/api/src/opendirector_api/creation.py、localization.py、domain/creation/commands.py、creation.schema.json、generated.ts、两语言 errors.ts、agent/tools.py、pyproject.toml 等)。PR 还整体重生成了一次 creation.schema.json,其中夹带了与本功能无关的工具描述改写,放大了冲突面。
修:剔除无关描述改动,rebase 后重跑 scripts/generate_contracts.py。

2. major — 用了 Field(exclude_if=...),但依赖仍是 pydantic>=2

packages/core/src/opendirector/domain/creation/editors.py:158-159 依赖 exclude_if,而 pyproject.toml:14 是 "pydantic>=2,<3"。exclude_if 是 pydantic 2.12 才引入的关键字;更旧的 2.x 会把它塞进 json_schema_extra 变成静默 no-op,于是空 fonts / overlays 照旧被序列化,"空则省略"的契约失效(对应测试会失败)。本地 pydantic 2.13.4 上行为正确。
修:pydantic>=2.12。

3. major — 新阈值绕开了 rule_facts 单一来源,Python / TS 各写一遍

editors.py:158-176(fonts 16、overlays 2000、text 4096)对 src/canvas/timelineText.ts:83,85,126,127;字体 32 MiB 在 packages/core/src/opendirector/media/fonts.py:14 与 src/canvas/timelineTextRenderer.ts 各有一份字面量;64 MiB 总量在 application/creation_timeline.py 与 application/creation_timeline_packages.py 各有一份。main 刚把跨语言限值收敛到 domain/rule_facts.py → src/contracts/ruleFacts.generated.ts。
修:把这几组数字加进 rule_facts.py,TS 侧消费生成常量。

4. major — 后端错误语种方向与仓库约定相反,同一文件内还混用

packages/core/src/opendirector/application/creation_timeline.py:41,45,50、media/fonts.py:38,44、application/creation_timeline_packages.py 在领域层写英文,再在 localization.py 用消息文本精确匹配还原中文;而同一个 creation_timeline.py:34 又是中文。未列入映射表的消息(改一个标点、以后新增、CLI/Agent 出口完全不过该表)会把英文直接暴露给中文用户。
修:领域层保持中文,按错误码而非消息文本查表(对齐 ENGLISH_BY_CODE 的做法)。

5. minor — src/canvas/timelineExport.ts:113-114

含文字资源时直接抛 errors.export.textUnsupported,但 timeline.action.exportFcpXml / exportZip 入口没有随之禁用,用户点了才报错。


已核对无问题:时间线包解压与炸弹防护(成员名白名单、成员集合精确匹配、4096 项 / 8 MiB 中央目录 / 512 MiB 归档 / 2 GiB 展开上限、逐条 size+CRC+SHA-256、ZIP64 EOCD 前置拒绝);落盘路径从不用归档成员名(infrastructure/execution_files.py 的 O_NOFOLLOW + O_EXCL);帧数学与预览/导出一致(两侧都是 ceil(t*fps-1e-9),overlay 结束时间计入时长的方式相同);i18n 两语言键集合一致(timeline.ts 190/190、errors.ts 604/604);main 上不存在既有字幕/文字实现,无重复。

## summary

- Integrate main's workspace modules, storage log and application ports
  while retaining editable text and platform file-access protections.
- Preserve active references when sources or groups are hidden, including
  prompt edits, persisted saves and pinned-reference metadata.
- Publish shared text/font budgets, require Pydantic 2.12 and retain
  accurate optional serialization fields at that minimum version.
- Preserve stable bilingual error codes through HTTP, CLI and Agent;
  explain disabled FCPXML and legacy ZIP actions with export alternatives.
- Keep native engine workspaces stable across resumed conversations and
  bound browser font loading by actual distinct byte fingerprints.
- Record shared validation and the remaining native Windows ACL repair
  and acceptance tasks. Keep the checkpoint Draft.

## validation

- Complete Python: 1,306 passed, 56 platform/capability skips.
- Complete Node: 714 passed; minimum Pydantic 2.12 checks: 77 passed.
- Build, generated contracts, i18n, browser manifest/locale and four
  import-boundary contracts passed.
- Five real browser suites passed: editing, rendering, font coverage,
  cross-project editable packages/publications and no-text workflow.
- Independent shared-code review finding verified RED to GREEN.

Refs: ThinkFlowLab#87
## summary

- Journal owner ACL deltas at the native setter's successful write,
  preserving external denies through retries and exceptional cleanup.
- Resume validated DeepSeek workspaces without rewriting existing ACLs
  or retaining file probes that block ordinary PowerShell writers.
- Add tracked Windows browser process ownership, isolated environments
  and native memory sampling, with real host and WinAPI regressions.
- Retain existing business assertions and record native Windows, wheel
  and seven-group browser acceptance with explicit platform limits.

## validation

- Complete Python: 1,368 passed, 15 skipped; Node: 720 passed.
- Related native regressions: 81 passed; wheel: 448 passed, 7 skipped.
- Seven browser groups, Windows wheel build and fresh install passed.
- Contracts, i18n, browser checks, four import contracts and build passed.
- Existing POSIX gates and WinError 1314 file-symlink limit documented;
  no test deletion, broader skips or sandbox relaxation.

Refs: ThinkFlowLab#87, ThinkFlowLab#193
Qing7364 added a commit to Qing7364/OpenDirector that referenced this pull request Nov 9, 2026
## summary

- Journal owner ACL deltas at the native setter's successful write,
  preserving external denies through retries and exceptional cleanup.
- Resume validated DeepSeek workspaces without rewriting existing ACLs
  or retaining file probes that block ordinary PowerShell writers.
- Add tracked Windows browser process ownership, isolated environments
  and native memory sampling, with real host and WinAPI regressions.
- Retain existing business assertions and record native Windows, wheel
  and seven-group browser acceptance with explicit platform limits.

## validation

- Complete Python: 1,368 passed, 15 skipped; Node: 720 passed.
- Related native regressions: 81 passed; wheel: 448 passed, 7 skipped.
- Seven browser groups, Windows wheel build and fresh install passed.
- Contracts, i18n, browser checks, four import contracts and build passed.
- Existing POSIX gates and WinError 1314 file-symlink limit documented;
  no test deletion, broader skips or sandbox relaxation.

Refs: ThinkFlowLab#87, ThinkFlowLab#193
## summary

- Consume ACL removal deltas at successful native writes and refresh
  Claude skill aliases safely when continuing the same session.
- Preserve uncertain POSIX outputs instead of deleting a replacement
  pathname, while retaining exclusive creation and error propagation.
- Discover PATH Python in CI, render live text move/trim previews,
  and align hidden-reference browser checks with shared semantics.
- Add regressions, review evidence and a focused bilingual Windows
  follow-up; keep historical platform results tied to their revisions.

## validation

- Python: 1321 passed, 74 platform/capability skips; Node: 721 passed.
- Full browser gate: 19/19 passed on the second complete run; initial
  structured-editor timeout and successful focused rerun recorded.
- Real text editing, render, coverage, archive and hidden references
  passed; build, contracts, i18n and four import boundaries passed.
- Independent repair review found no further required code fix.
- New native Windows cleanup cases and rebuilt wheel remain pending.

Refs: ThinkFlowLab#87
## summary

- Reject an already broken oplock at the native setter boundary, keeping
  successful-write receipts and one-time cleanup consumption intact.
- Strengthen the real concurrent cleanup regression and retain actual
  post-write fault injection after the added pre-write check.
- Record native Windows follow-up, fresh wheel and browser evidence,
  preserving prior results with their original revision boundaries.

## validation

- Complete Python: 1,378 passed, 17 skipped; Node: 721 passed.
- Related modules: 184 passed, 3 skipped; ACL modules: 77 passed.
- Fresh wheel: 195 passed, 3 skipped; three browser groups passed.
- Build, contracts, i18n, browser checks and four import contracts passed.
- Retain POSIX gates and the Windows file-symlink privilege limitation;
  no test deletion, expanded skips or sandbox relaxation.

Refs: ThinkFlowLab#87, ThinkFlowLab#193
Qing7364 added a commit to Qing7364/OpenDirector that referenced this pull request Nov 9, 2026
## summary

- Reject an already broken oplock at the native setter boundary, keeping
  successful-write receipts and one-time cleanup consumption intact.
- Strengthen the real concurrent cleanup regression and retain actual
  post-write fault injection after the added pre-write check.
- Record native Windows follow-up, fresh wheel and browser evidence,
  preserving prior results with their original revision boundaries.

## validation

- Complete Python: 1,378 passed, 17 skipped; Node: 721 passed.
- Related modules: 184 passed, 3 skipped; ACL modules: 77 passed.
- Fresh wheel: 195 passed, 3 skipped; three browser groups passed.
- Build, contracts, i18n, browser checks and four import contracts passed.
- Retain POSIX gates and the Windows file-symlink privilege limitation;
  no test deletion, expanded skips or sandbox relaxation.

Refs: ThinkFlowLab#87, ThinkFlowLab#193
## summary
- Assign remaining integration, native ACL validation, fixes, review and final acceptance to Windows.
- Define source freeze, targeted retesting, CI ownership and evidence requirements to avoid repeated cross-device handoffs.
- Publish aligned Chinese and English handoff instructions.
## summary
- Merge main's connection-scoped voice library and benchmark gate while
  retaining timeline text, fonts, editable packages and locked dependencies.
- Confirm committed ACL removals after final-check and release conflicts;
  preserve native receipts, external identical denies and original errors.
- Read Agent voice recordings through the shared execution-file boundary,
  reject hard links, and cover real native writers and handle cleanup.
- Isolate the strict native handle-count test from unrelated finishing
  threads; keep its original failure checks and equality assertion.

## validation
- Native ACL modules: 94 passed, no skips.
- Native/voice/execution-file focused batch: 214 passed, one existing
  Windows symlink-permission skip.
- Integration Node selection: 46 passed; TypeScript check passed.
- Regenerated contracts check, locked editable install and pip check passed.

Refs: ThinkFlowLab#87
## summary
- Recheck the editor transaction and captured snapshot when background
  hydration finishes, before installing content or its version basis.
- Exercise a delayed real projection during stage rendering and retain
  strict publication refusal, retry and immutable provenance assertions.
- Record the demonstrated asynchronous projection risk in development
  lessons without weakening publication version checks.

## validation
- The formal structured-editor regression fails without the fix and
  passes with it in native Windows Chrome.
- TypeScript check passed. The later source edit only adds explanatory
  comments; broad frontend and package validation follows this freeze.

Refs: ThinkFlowLab#87
## summary
- Record main integration, real ACL write/release windows, scoped source
  freezes, failed attempts and final Windows/browser/wheel evidence.
- Preserve the earlier full Python result at its tested revision and
  document unchanged Python inputs after the frontend correction.
- Update historical plans and both handoffs; leave final delivery SHA,
  PR metadata and final-head CI to the subsequent delivery receipt.

## validation
- All 875 frozen runtime/test/build inputs remain byte-identical.
- Source freeze Release checks 42569337698 passed, including Python,
  19 browser workflows, the voice fixture and assistant panels.
- Latest clean Windows wheel regression: 324 passed, 3 existing skips.
- Documentation diff check passed; no Windows functionality rerun for
  these status and evidence changes.

Refs: ThinkFlowLab#87
## summary

- Merge main 6310097 while retaining validated native workspaces and
  recovering missing Codex rollouts with the full conversation history.
  Preserve provider download SSRF checks and upstream tool/UI fixes.
- Reject acknowledged ACL installations when their guard cannot confirm
  ownership. Preserve that object's uncertain ACL, block Agent execution
  and release resources; confirmed installations still roll back.
- Change after_write installation conflicts from retry to explicit
  failure. Preserve pre-write retries, ordinary setter-error rollback
  and the existing committed-cleanup confirmation contract.
- Add ownership regressions, eleven native interleavings and a bilingual
  seven-module Windows handoff with explicit JSONL evidence capture.

## validation

- Mac source: 430 focused backend tests and 734 Node tests passed.
- Native/control-flow modules with OPENDIRECTOR_REAL_CLI=1: 78 passed,
  76 Windows-specific tests skipped.
- Production build, generated contracts, i18n (2996 keys), browser
  locale/manifest checks and all four import boundaries passed.
- The eleven new WinAPI cases remain unexecuted on Mac. Focused Windows
  acceptance is pending; historical media/wheel evidence keeps its SHA.

Refs: ThinkFlowLab#87
@kunkunblueberry

Copy link
Copy Markdown
Collaborator

CI 在 3cb30b64 上红在你自己新增的那段脚手架,而不是产品代码。我按失败日志和代码路径定位了一下,给了个不依赖时序的写法。

失败点

Release checks(run 42595923987)走到 --publish 的 stage 段:

locator.waitFor: Timeout 20000ms exceeded.
  - waiting for getByRole('button', { name: 'Added to canvas', exact: true }) to be visible
    at tests/browser/structured_editors.mjs:237:8

:232-234 那次重试点击是发生了的(422 那条 alert 已经在 :229 等到),所以是重试的 publish 没有完成,不是按钮文案变了。

为什么会卡住

structured_editors.mjs:187-201 覆写了 projection.read,而 "Add preview video to canvas" 这条路径在 useWorkspaceEditor.ts 里是:

const ids = await publication.publish(outputs, task);   // :196
const projection = workspaceProjection(current.id);
const snapshot = client.snapshot;
const next = await projection.read(snapshot);           // :199  ← 被覆写的正是这里

也就是说这个 hold 落在前台 publish 路径上,不是注释里说的 "background projection"——两者共用同一个方法。

而 :193 的挂起只有一个出口,:194 的 else if (release && director.data.duration === 0.5),必须再有一次 read 以 duration === 0.5 进来才会 resolve。这就是问题所在:能否解开取决于 read 的先后顺序。

具体地,如果那次 0.5 的 read(渲染保存时的 :136)在 release 还没被赋值之前就过去了,else if 直接跳过;之后任何一次 6 的 read 命中 :190 就会永久 park,而后面不会再有 0.5 的 read 来解开它。于是 :199 永远不返回,publish 不完成,Added to canvas 出不来 —— 正好 20 秒超时。本地跑得快、CI 上调度不同就会翻车,属于典型的时序依赖。

建议的改法:让测试自己决定何时放行

不要依赖"下一次 read 恰好是 0.5",把 resolve 交给测试:

await page.evaluate(async (id) => {
  const { workspaceProjection } = await import("/src/backend/workspace.ts");
  const projection = workspaceProjection(id);
  const client = projection.client;
  const read = projection.read;
  let restored = false;
  const restore = () => {
    if (restored) return;
    restored = true;
    projection.read = read;
  };
  // Expose the release so the test decides when to stop holding, instead of
  // waiting for another read to arrive with a particular duration.
  window.__releaseStageProjection = () => {
    const release = window.__stageRelease;
    window.__stageRelease = undefined;
    restore();
    queueMicrotask(() => release?.());
  };
  projection.read = async (snapshot) => {
    const next = await read.call(projection, snapshot);
    const director = snapshot.editorDocuments.find((doc) => doc.kind === "director");
    if (!window.__heldStageProjection && director?.data.duration === 6) {
      window.__heldStageProjection = true;
      await new Promise((resolve) => { window.__stageRelease = resolve; });
    }
    return next;
  };
  client.install({ ...client.snapshot });
}, f.id);
await page.waitForFunction(() => window.__heldStageProjection === true);

然后在你希望"acknowledged render 之后、React 装上新的 history 引用之前"的那一刻显式放行:

await page.evaluate(() => window.__releaseStageProjection());

两点理由:

  • 去掉顺序依赖:挂起一定会有出口,不再要求某次特定 duration 的 read 刚好排在后面。你本来要构造的时序(旧快照的 read 挂在 ack 之后才被放行)依然成立,但变成由测试控制而不是由调度决定。
  • 一定恢复:原写法只在 0.5 分支里 projection.read = read。一旦解不开,覆写就留在页面上。workspaceProjection 是模块级缓存(workspace.ts:29-37,const projections = new Map(...)),所以这会污染同一页后续所有步骤,后面的失败会被误算到无关代码头上,排查成本很高。上面的 restore() 在放行时无条件执行。

另外两个会咬人的小点

  1. :190 / :194 的 director.data.duration 没有可选链。快照里没有 director 文档时就是 TypeError,而它会在 read 内部抛出,调用方只看到一次笼统的刷新失败(useWorkspaceEditor.ts:137-138 会包成 "编辑器刷新失败")。改成 director?.data.duration。
  2. 如果这是要证明"迟到的旧快照不能把已保存的 basis 回滚",hook 的落点可能选错了层:addLinkedOutputs 与编辑器保存(:136)共用 projection.read,所以 hold 同时作用于前台 publish。想只影响"后台投影",更贴近意图的做法是 hook client.install / 快照消费,而不是 read;至少注释里应该写明这个 hold 也会挡住 publish。

说明

我本地没有 node_modules(离线),没能跑起浏览器套件复现,以上是从 CI 日志 + 上述代码路径推出来的。改完建议在 CI 上连跑两次确认不是巧合通过。

顺带:这个 PR 之前审查提的四条(pydantic>=2.12、TIMELINE_* 归入 rule_facts.py、错误消息改为 timeline_error_message(code) 按码查表、rebase 解冲突)我已经复查过,都落地了。现在只差这条 CI。

## summary

- Invalidate scheduled autosaves before editor saves, media
  publication and timeline imports, including hidden-page flushes.
- Preserve queued writes, explicit canvas draft saves and fixed
  publication versions; reject stale-project callbacks first.
- Exercise an expired real autosave at the editor acknowledgement
  boundary and isolate and clean up the held projection test.
- Record the controlled reproduction and focused validation without
  claiming the exact CI schedule or new Windows acceptance.

## validation

- Structured publication regression fails before the fix and passes
  twice afterward; all five focused browser workflows pass.
- All 734 Node tests, TypeScript and production build pass.
- i18n validates 2996 keys; browser locale and manifest checks pass.
## summary

- Close the focused Windows handoff at d0d8999 with 154 passing tests,
  zero skips and the complete eleven-install/twelve-cleanup matrix.
- Record the host ACL prerequisite failure, authorized restriction,
  immutable input hashes and exact native/CLI evidence boundaries.
- Update both handoffs and the current delivery plan while retaining
  historical full-suite, media and wheel revisions.

## validation

- Seven focused Python modules: 154 passed, 0 failed, 0 skipped.
- JSONL, JUnit, console and exit-code cross-check passed.
- Independent read-only review and 878-input byte comparison passed.
- git diff --staged --check passed.

Refs: ThinkFlowLab#87
## summary

- Observe actual media responses before reload, then use a bounded
  navigation budget and the existing media deadline after readiness.
- Keep successful-response and persisted voice/result assertions, and
  verify the reopened player's asset identity, bytes and playback.
- Release the response listener and deadline timer on every exit.

## validation

- Bilingual voice workflow passed with Chromium 145 and Playwright 1.58.2.
- Controlled 17-second navigation failed before and passed after this
  change; the missing-media negative control still fails as intended.
- Exact staged bytes match the tested source; independent read-only
  review, node --check and git diff --staged --check passed.

Refs: ThinkFlowLab#87
## summary

- Preserve the failed delivery CI and all scoped voice probes, including
  unsuccessful injections and the intentional media-outage control.
- Record c19781a as the browser-test freeze with its exact input hashes,
  explicit navigation budget change and stronger media assertions.
- Retain native acceptance at d0d8999 and close both handoffs and the
  current plan without repeating unchanged Windows validation.

## validation

- Cold and normal bilingual voice workflows passed; missing media is
  still rejected by the fifteen-second media deadline.
- 878 frozen inputs match and all 877 native-protected inputs remain
  unchanged, including 242 Python files.
- Independent read-only review and git diff --staged --check passed.

Refs: ThinkFlowLab#87
## summary

- Integrate the fixed main snapshot with Kling video, voice settings
  repair, version 0.1.2 and review guidance. Retain timeline contracts,
  bilingual errors, validated session recovery and safe Windows links.
- Use the canvas model resolver for missing assistant generation choices.
  Keep explicit selections and prove loading cannot change the model
  saved by new nodes, including an old-frontend negative control.
- Observe reopened voice media through standard browser APIs so preview
  runs retain asset identity, byte hash and real playback assertions.

Refs: ThinkFlowLab#87
## summary

- Record the fixed-main source freeze, default-selection regression and
  preview-safe voice observer, with positive and negative evidence.
- Record 154 native passes, all 23 WinAPI windows and 308 installed-wheel
  passes, plus the bilingual wheel UI and actual fixture media.
- Preserve failed attempts, source/input boundaries, the file-symlink
  privilege limit and CI status at document creation. Close Windows
  handoff work while retaining historical evidence and Draft review.

Refs: ThinkFlowLab#87
## summary

- Publish the existing Chinese and English timeline screenshots with
  their hashes, original capture context and visible draft notice.
- Map original acceptance revisions to equivalent email-normalized
  commits while retaining their historical test evidence.
- Record unchanged runtime inputs and no repeated Windows tests.

## validation

- Staged screenshots match the inspected original bytes and hashes.
- All 18 rewritten commits preserve their trees and merge topology.
- Staged documentation diff and relative image targets checked.

Refs: ThinkFlowLab#87
@Qing7364
Qing7364 force-pushed the codex/issue-87-timeline-text branch from 59fc9aa to 9db7cf8 Compare November 10, 2026 02:30
@Qing7364
Qing7364 marked this pull request as ready for review November 10, 2026 02:42

@kunkunblueberry kunkunblueberry left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复查通过:上次那条 CI 阻断已经修好,我之前的发现全部落实。剩余 3 条是 minor/nit,不阻塞。

CI 阻断(上次的发现)— 已修,且我确认了 CI 里真的跑到

structured_editors.mjs 那段脚手架被整体重写了,思路换得更对:

  • 不再 hook projection.read 去挡前台 publish,而是拦截 useWorkspaceDocument.ts 里到期的 autosave 回调(window.setTimeout 包装,按 stack 匹配 + 450/900 延迟白名单),在 baseline 被设成 0.5 版本时 restore() 后 queueMicrotask 触发一次,证明过期 autosave 不会把渲染前的内容写回。
  • projection.read 的挂起只作用于显式注入的那个快照(snapshot === injected && held === 0),后续前台 read 不再被挡——正好修掉我上次说的"hold 落在 publish 路径上"。
  • 释放条件加了 director?.revision > original.revision && director?.data.duration === 0.5,director?. 的可选链也补上了(上次并列提的那条)。
  • 最关键的是加了自证断言::273-274 断言 {held:1, released:1, returned:true, restored:true},:275 断言 autosave 恰好被调用 1 次,:277 断言认可后的 revision === 3。即使将来再次卡住,也会以明确的断言失败暴露,而不是 20 秒后在一个 locator 上超时——这点比我建议的写法还好。

CI 证据(当前 head 9db7cf83,run 42743289694):

02:38:52 === structured editors: tests/browser/structured_editors.mjs ===
02:39:15 PASS director real MP4: confirmed stage snapshot, rejection retains rendered output, retry and reopen preserve provenance
02:39:16 PASS structured editors (24.0s)

那一行 PASS 只有在 :273-278 的断言全部通过后才会打印,所以新机制确实执行并通过了。

之前 4 条 blocker/major — 逐条复核

上次的发现 现在
与 main 冲突 merge-base = e0b411f1,MERGEABLE / CLEAN,与最新 main 无文件重叠
exclude_if 需要 pydantic ≥2.12 但依赖写 >=2 pyproject.toml:"pydantic>=2.12,<3"
阈值 Python/TS 双写,绕过 rule_facts rule_facts.py:20-21 定义 TIMELINE_FONT_LIMIT / TIMELINE_OVERLAY_LIMIT / 文本长度 / 字体字节,并入 facts_payload();editors.py:9,162-163 消费这些常量
领域层英文报错 + 消息文本查表 改为 timeline_error_message(code),按稳定码取文案(creation_timeline.py:41-50)
(minor)文字资源存在时 FCPXML/ZIP 按钮仍可点 TimelineEditor.tsx:1221,1228 按 hasTextResources 禁用,:1222,1229 给 timeline.text.unsupportedExchange 提示,:1243 另有说明

另外核对:src/i18n/messages 两语言键集合 3002 / 3002,无单侧键。

仍然存在的 3 条(都不阻塞)

  1. minor — 在检查器里手输时间不做帧对齐。 TimelineTextInspector.tsx:52 提交的是 Number(e.target.value) 原值,step={1 / fps}(:48)只影响步进器;而轨道拖动用 Math.round(t * fps) / fps(timeline.ts:212,234,302),契约取帧用 Math.ceil(t * fps - 1e-9)(timelineText.ts:22-23)。24fps 下输入 1.001 会按契约落到第 25 帧,但检查器显示仍是 1.001。三处共用同一个对齐函数即可。
  2. nit — "noto-sans-cjk-sc-regular" 仍是硬编码字符串,出现在 TimelineEditor.tsx:713 与 TimelineTextInspector.tsx:214 两处,建议提取常量。
  3. nit — public/fonts/NotoSansCJKsc-Regular.otf 16.4 MB 进 git 并随 dist/ 进 wheel(OFL 许可与 manifest.json 溯源是齐的,只是安装体积)。

另外提一句

tests/browser/kling_video.mjs 相对 main 有 +91/−21:新增的是一段 route-gated 的 assistant 默认模型选择断言(assistantPath + assistantGate),属于你说的 assistant default-selection 修复,和字幕/overlay 无关。功能上没问题、CI 也过,但它是别的功能自己的浏览器用例,落在本 PR 里会让以后的 blame 变模糊。可以接受,只是记录一下。

我的复查覆盖范围,请不要当成全文通读

  • 我逐条复核了上面列的每一项,并读了重写后的 structured_editors.mjs 全段。
  • 没有重读全部 180 个文件的当前版本;新增的 agent/native.py(相对 main 约 +173/−72)、owner_rights.py、directory_links.py、windows_execution_files.py 只做了抽查。PR 描述里提到这些是 fail-closed 的 ACL 与 Windows symlink 相关改动,且 Windows 侧未重跑——这部分建议由熟悉 Windows 文件权限的人再确认一次。

基于以上,审查结论改为通过(先前 4 条 blocker/major 与 CI 阻断都已闭环)。

@Qing7364

Copy link
Copy Markdown
Contributor Author

@kunkunblueberry Thanks for the review. The original findings have been addressed, and the projection-test isolation/cleanup and stale-autosave regression are covered. Windows acceptance is complete, and bilingual screenshots are now attached.

@kunkunblueberry
kunkunblueberry merged commit 1eaa873 into ThinkFlowLab:main Nov 10, 2026
1 check passed
@kunkunblueberry

Copy link
Copy Markdown
Collaborator

LGTM,thanks!

@cursor cursor Bot mentioned this pull request Nov 10, 2026
4 of 5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:canvas Canvas, nodes and direct manipulation area:timeline Timeline, subtitles and export type:feat New capability or behaviour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants